package common;

import java.util.HashSet;

import common.Enums.MessageType;

/**
 * @author alex 
 * Performs interop between messages/replies and strings. Specifically, this 
 * class will convert messages and replies to strings, and it will convert 
 * strings to message and replies. The strings can be sent directly across the 
 * network.  That way, we can use the objects everywhere else.
 */
public final class Parser
{
    /**
     * Default constructor is private to prevent this class from being 
     * instantiated. 
     */
    private Parser()
    {
    }
    
    /**
     * Converts the specified message to a string that can be sent across the 
     * network.
     * @param m The message to convert.
     * @return The message as a string.
     */
    public static String MessageToString(Message m)
    {
        try
        {
            if (m == null || m.GetMessageType() == MessageType.NULL)
            {
                return null;
            }
            
            String s = "M ";
            s += m.GetMessageType().toString().toUpperCase();
            
            HashSet<String> parameters = m.GetAllParameters();
            if (parameters.size() > 0)
            {
                s += " ";
                for (String parameterName : parameters)
                {
                    String parameterValue = m.GetParameter(parameterName);
                    s += parameterName + ":" + parameterValue + ",";
                }
                s = s.substring(0, s.length() - 1);
            }
            
            String content = m.GetContent();
            if (content != null)
            {
                s += " ";
                s += content;
            }
            
            return s;
        }
        catch (Exception e)
        {
            return null;
        }
    }
    
    /**
     * Converts the specified reply into a string that can be sent across the 
     * network.
     * @param r The reply to convert.
     * @return The reply as a string.
     */
    public static String ReplyToString(Reply r)
    {
        try
        {
            if (r == null || r.GetId() < 0)
            {
                return null;
            }
            
            String s = "R ";
            s += r.GetId();
            
            String text = r.GetText();
            if (text != null)
            {
                s += " ";
                s += text;
            }
            
            return s;
        }
        catch (Exception e)
        {
            return null;
        }
    }
    
    /**
     * Converts the specified string into a message object.
     * @param s The string to convert.
     * @return The message object.
     */
    public static Message StringToMessage(String s)
    {
        try
        {
            if (s == null || !Parser.GetNetworkMessageType(s).equals("M"))
            {
                return null;
            }
            
            String[] messageParts = s.split(" ", 4);
            if (messageParts.length < 1)
            {
                return null;
            }
            if (!messageParts[0].trim().equals("M"))
            {
                return null;
            }
            Message m = new Message(MessageType.valueOf(messageParts[1].toUpperCase()));
            
            if (messageParts.length >= 3)
            {
                String[] parameterParts = messageParts[2].split(",");
                for (int i = 0; i < parameterParts.length; i++)
                {
                    String[] parameterPair = parameterParts[i].split(":", 2);
                    if (parameterPair.length != 2)
                    {
                        continue;
                    }
                    m.SetParameter(parameterPair[0], parameterPair[1]);
                }
                
                if (m.GetAllParameters().size() == 0)
                {
                    m.SetContent(messageParts[2]);
                }
            }
            
            if (messageParts.length >= 4)
            {
                if (m.GetAllParameters().size() == 0)
                {
                    m.SetContent(messageParts[2] + " " + messageParts[3]);
                }
                else
                {
                    m.SetContent(messageParts[3]);
                }
            }
            
            if (m.GetMessageType() == MessageType.NULL)
            {
                return null;
            }
            return m;
        }
        catch (Exception e)
        {
            return null;
        }
    }
    
    /**
     * Converts the specified string into a reply object.
     * @param s The string to convert.
     * @return The reply object.
     */
    public static Reply StringToReply(String s)
    {
        try
        {
            if (s == null || !Parser.GetNetworkMessageType(s).equals("R"))
            {
                return null;
            }
            
            Reply r = new Reply();
            
            String[] replyParts = s.split(" ", 3);
            if (replyParts.length < 3)
            {
                return null;
            }
            
            if (!replyParts[0].trim().equals("R"))
            {
                return null;
            }
            
            r.SetId(Integer.parseInt(replyParts[1].trim()));
            r.SetText(replyParts[2].trim());
            
            if (r.GetId() < 1)
            {
                return null;
            }
            return r;
        }
        catch (Exception e)
        {
            return null;
        }
    }
    
    /**
     * Determines the type of network message denoted by the specified string.
     * If the network message is a Message, "M" will be returned.
     * If the network message is a Reply, "R" will be returned.
     * In any other case, null will be returned.
     * @return A string denoting the message type.
     */
    public static String GetNetworkMessageType(String s)
    {
        try
        {
            if (s == null)
            {
                return null;
            }
            
            String[] parts = s.split(" ");
            if (parts.length < 1)
            {
                return null;
            }
            
            String messageType = parts[0].trim().toUpperCase();
            
            if (messageType.equals("M") ||
                messageType.equals("R"))
            {
                return messageType;
            }
            return null;
        }
        catch (Exception e)
        {
            return null;
        }
    }
}